package com.yubest.springboothello.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class NettyServer implements ApplicationRunner {

    @Value("${netty.server.port}")
    private int port;

    @Value("${netty.server.path}")
    private String path;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        new Thread(() -> {
            try {
                this.start();
            } catch (Exception e) {
                log.error("启动 netty server 失败", e);
            }
        }).start();
    }

    public void start() throws Exception {
        log.info("开始启动netty server...");
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            // 绑定线程池
            sb.group(boss, work)
                    // 指定使用的channel
                    .channel(NioServerSocketChannel.class)
                    // 绑定客户端连接时候触发操作
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel sc) throws Exception {
                            //websocket协议本身是基于http协议的，所以这边也要使用http解编码器
                            sc.pipeline().addLast(new HttpServerCodec());
                            //以块的方式来写的处理器
                            sc.pipeline().addLast(new ChunkedWriteHandler());
                            sc.pipeline().addLast(new HttpObjectAggregator(8192));
                            sc.pipeline().addLast(new NettyMessageHandler());
                            // ws://127.0.0.1:8081/ss
                            sc.pipeline().addLast(new WebSocketServerProtocolHandler(path, null, true, 65536 * 10));
                        }
                    });
            // 服务器异步创建，绑定监听端口
            ChannelFuture cf = sb.bind(port).sync();
            log.info("netty server 已启动，正在监听：{}", cf.channel().localAddress());
            // 关闭服务器通道
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("netty server 启动异常", e);
        } finally {
            // 释放线程池资源
            boss.shutdownGracefully().sync();
            work.shutdownGracefully().sync();
        }
    }
}
